package com.yanjiali.service.impl;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yanjiali.constant.QFConts;
import com.yanjiali.model.req.QianFanChatBean;
import com.yanjiali.model.resp.QFAccessTokenBean;
import com.yanjiali.model.resp.QianFanResponseBean;
import com.yanjiali.properties.BaiDuQianFanProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;

import javax.annotation.PostConstruct;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.List;


/**
 * 千帆流式调用返回业务实现类
 */
@Slf4j
@Service
public class GptQianFanServiceImpl {
    //webflux的client
    private WebClient webClient;

    @Autowired
    private BaiDuQianFanProperties baiDuQianFanProperties;

    @Autowired
    private RestTemplate restTemplate;  //rest Http请求类

    /**
     * token初始获取时间
     */
    private static Long beginTime = 820454400L;

    /**
     * 存储千帆token
     */
    private static String token = "";

    //用于读取第三方的返回结果
    private ObjectMapper objectMapper = new ObjectMapper();

    @PostConstruct
    public void postConstruct() {
        //创建webflux的client
        this.webClient = WebClient.builder()
                //填写对应的api地址
//                .baseUrl(baiDuQianFanProperties.getGet_answer_url())  //TODO 这里我没有分地址
                //设置默认请求类型
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .build();
    }

    /**
     * 返回流式结果
     * @param content   发送的消息
     * @return
     */
    public Flux<QianFanResponseBean> doQianFanStream(String content) {
        if(checkTokenPastDue()) {   //判断token是否过期
            token = getAccessTokenUsingRestTemplate();  //获取token
        }
        //组装请求参数
        QianFanChatBean requestBean =  getRequestData(content);
        //构建请求json
        String paramJson = JSONUtil.toJsonStr(requestBean);;
        //使用webClient发送消息
        return this.webClient.post()
                //请求uri
                .uri(baiDuQianFanProperties.getGet_answer_url() + token)
                //设置流式响应
                .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_EVENT_STREAM_VALUE)
                .contentType(MediaType.APPLICATION_JSON)
                .acceptCharset(Charset.forName("UTF-8"))
                .body(BodyInserters.fromValue(paramJson))
                .retrieve()
                .bodyToFlux(String.class)
                //接收到消息的处理方法
                .flatMap(result -> handleWebClientResponse(result));

    }

    /**
     * 收到消息的处理方法
     * @param resp
     * @return
     */
    private Flux<QianFanResponseBean> handleWebClientResponse(String resp) {
        log.info("百度千帆返回:======>{}",resp);
        QianFanResponseBean result = JSON.parseObject(resp, QianFanResponseBean.class);
        //is_end=true结束标识
        if (result.isIs_end()){
            return Flux.empty();
        }
        try {
            //返回获得的结果
            return Flux.just(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 获取对应token
     * @return
     */
    private String getAccessTokenUsingRestTemplate() throws JSONException {
        // 设置请求参数
        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
        requestBody.add("grant_type", "client_credentials");
        requestBody.add("client_id", baiDuQianFanProperties.getClient_id());
        requestBody.add("client_secret", baiDuQianFanProperties.getClient_secret());

        // 设置请求头
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        // 发送POST请求
        ResponseEntity<String> response = restTemplate.exchange(
                baiDuQianFanProperties.getGet_token_url(),
                HttpMethod.POST,
                new HttpEntity<>(requestBody, headers),
                String.class);

        // 解析返回结果
        String responseBody = response.getBody();

        QFAccessTokenBean tokenBean = JSON.parseObject(responseBody, QFAccessTokenBean.class);
        return tokenBean.getAccess_token(); //获取其中的token字符串
    }

    /**
     * 检查token是否过期
     * @return
     */
    private boolean checkTokenPastDue() {
        Long engTime = LocalDateTime.now().toInstant(ZoneOffset.UTC).toEpochMilli() / 1000;
        Long midTime = engTime - beginTime;
        Long day = midTime / 60 / 60 / 24;
        if(day > 29) { // TODO 千帆token有效期 30天
            return true;
        }
        return false;
    }

    /**
     * 获取请求参数
     * @param content
     * @return
     */
    public static QianFanChatBean getRequestData(String content) {
        QianFanChatBean requestBean = new QianFanChatBean();
        List<QianFanChatBean.QFMessage> messages = new ArrayList<>();
        QianFanChatBean.QFMessage message = new QianFanChatBean.QFMessage();
        message.setRole(QFConts.QFRole.USER);
        message.setContent(content);
        messages.add(message);
        requestBean.setMessages(messages);
        requestBean.setStream(true);    //设置流式调用接口
        return requestBean;
    }
}
